home *** CD-ROM | disk | FTP | other *** search
/ Fritz: All Fritz / All Fritz.zip / All Fritz / FILES / PROGNG_C / TPTC17GS.LZH / TPCEXPR.INC < prev    next >
Text File  |  1988-05-03  |  24KB  |  964 lines

  1.  
  2. (*
  3.  * TPTC - Turbo Pascal to C translator
  4.  *
  5.  * (C) 1988 Samuel H. Smith (rev. 13-Feb-88)
  6.  *
  7.  *)
  8.  
  9.  
  10. (*
  11.  * expression parser
  12.  *
  13.  *)
  14. function pterm: string; forward;
  15.  
  16.  
  17. (********************************************************************)
  18. function iscall(var lv: string): boolean;
  19.    {see if the given lvalue is a function call or not}
  20. begin
  21.    iscall := lv[length(lv)] = ')';
  22. end;
  23.  
  24.  
  25. (********************************************************************)
  26. function typecast(ty: string; ex: string): string;
  27.    {generate a typecasted expression}
  28. begin
  29.    if pos(' ',ex) > 0 then
  30.       ex := '(' + ex + ')';
  31.    typecast := '(' + ty + ') ' + ex;
  32. end;
  33.  
  34.  
  35. (********************************************************************)
  36. procedure make_pointer(var expr: string);
  37.    {convert the expression into a pointer constant, if possible}
  38. var
  39.    sym:  symptr;
  40.    p:    integer;
  41.    nex:  string;
  42. begin
  43.    
  44.    sym := voidsym;
  45.    nex := expr;
  46.  
  47.    case(expr[1]) of
  48.       '*':
  49.          nex := copy(expr,2,255);
  50.       
  51.       '(':
  52.          begin          {possible typecast}
  53.             p := pos(')(*',expr);
  54.             if p = 0 then
  55.                nex := '&(' + expr + ')'
  56.             else
  57.                nex := copy(expr,1,p-1) + ' *) (' + copy(expr,p+3,255);
  58.          end;
  59.  
  60.       'a'..'z','A'..'Z','_':
  61.          begin          {pass pointer to strings/arrays}
  62.             sym := locatesym(expr);
  63.             if sym = nil then
  64.                sym := voidsym;
  65.  
  66.             if (sym^.symtype = ss_scalar) then
  67.                sym := sym^.parent;
  68.  
  69.             if (sym <> nil) and ((sym^.symtype = ss_array) or
  70.                                  (sym^.symtype = ss_pointer)) then
  71.             begin
  72.                {nex := expr;}
  73.             end
  74.             else
  75.             
  76.             if expr[length(expr)-1] = '(' then    {remove () from calls}
  77.                nex := copy(expr,1,length(expr)-2)
  78.             else
  79.                nex := '&' + expr;
  80.          end;
  81.  
  82.       {else
  83.          nex := expr;}
  84.    end;
  85.  
  86. if debug then
  87. writeln('mp1: expr=',expr,' nex=',nex, ' ty=',typename[sym^.symtype]);
  88.  
  89.    expr := nex;
  90. end;
  91.  
  92.  
  93. (********************************************************************)
  94. function isnumber(var lv: string): boolean;
  95.   {see if the given value is a literal number}
  96. var
  97.    i: integer;
  98. begin
  99.  
  100.    case lv[1] of
  101.       '0'..'9','.':
  102.           ;
  103.       else
  104.          isnumber := false;
  105.          exit;
  106.    end;
  107.  
  108.    for i := 2 to length(lv) do
  109.       case lv[i] of
  110.          '0'..'9','.', 'x','X', 'A'..'F','a'..'f','L':
  111.             ;
  112.          else
  113.             isnumber := false;
  114.             exit;
  115.       end;
  116.  
  117.    isnumber := true;
  118. end;
  119.  
  120.  
  121. (********************************************************************)
  122. procedure subtract_base(var expr: string; base: integer);
  123.    {subtract the specified base from the given expression;
  124.     use constant folding if possible}
  125. begin
  126.  
  127. if debug then
  128. writeln(' base1=',base,' ex=',expr);
  129.  
  130.    if base <> 0 then
  131.    begin
  132.       if isnumber(expr) then
  133.          expr := itoa(htoi(expr) - base)
  134.       else
  135.       if base > 0 then
  136.          expr := expr + '-' + itoa(base)
  137.       else
  138.          expr := expr + '+' + itoa(-base);
  139.    end;
  140. end;
  141.  
  142.  
  143. (********************************************************************)
  144. function exprtype: char;
  145.    {determine expression type and return the printf code for the type}
  146. var
  147.    xt:      char;
  148.    sym:     symptr;
  149.    
  150. begin
  151.    case cexprsym^.symtype of
  152.       ss_scalar,
  153.       ss_func,     
  154.       ss_const,    
  155.       ss_builtin:    sym := cexprsym^.parent;
  156.       
  157.       else           sym := cexprsym;
  158.    end;
  159.    
  160.    if (sym = stringsym) {or (cexprsym = stringsym)} then
  161.       xt := 's'
  162.    else
  163.    case sym^.symtype of
  164.       s_char:    xt := 'c';
  165.       s_text:    xt := '@';
  166.       s_file:    xt := '!';
  167.       s_double:  xt := 'f';
  168.       s_bool:    xt := 'b';
  169.       s_int:     xt := 'd';
  170.       s_long:    xt := 'D'; { calling routine should convert to "ld" }
  171.       else       xt := '?';
  172.    end;
  173.  
  174. (**
  175. if debug then
  176. writeln(^M^J'..symtype id=',cexprsym^.id,
  177.                  ' ty=',typename[cexprsym^.symtype],
  178.                  ' p=',cexprsym^.parent^.id,
  179.                  ' xt=',xt);
  180. **)
  181.    exprtype := xt;
  182. end;
  183.  
  184.  
  185. (********************************************************************)
  186. function exprtype_id: string;
  187.    {return type identifier for current expression}
  188. begin
  189. (**
  190.    if (cexprsym^.symtype = ss_pointer) or
  191.       (cexprsym^.symtype = ss_array) then {hack?}
  192.       exprtype_id := cexprsym^.parent^.repid +'`1'
  193.    else
  194. **)
  195.    exprtype_id := cexprsym^.parent^.repid;
  196. end;
  197.  
  198.  
  199. (********************************************************************)
  200. function strtype(ty: char): boolean;
  201.    {see if the expression is a string data type or not}
  202. begin
  203.    case ty of
  204.       's','c':  strtype := true;
  205.       else      strtype := false;
  206.    end;
  207. end;
  208.  
  209.  
  210. (********************************************************************)
  211. function psetof:  string;
  212.    {parse a literal set; returns the set literal translated into
  213.     the form: setof(.....)}
  214. var
  215.    ex: string;
  216.  
  217. begin
  218.    ex := 'setof(';
  219.    if tok[1] <> ']' then
  220.       ex := ex + pterm;
  221.  
  222.    while (tok = '..') or (tok[1] = ',') do
  223.    begin
  224.       if tok = '..' then       
  225.          ex := ex + ',__,'
  226.       else
  227.          ex := ex + ',';
  228.  
  229.       gettok;
  230.       ex := ex + pterm;
  231.    end;
  232.  
  233.    if ex[length(ex)] <> '(' then
  234.       ex := ex + ',';
  235.    ex := ex + '_E)';
  236.    psetof := ex;
  237. end;
  238.  
  239.  
  240. (********************************************************************)
  241. function pterm:   string;
  242.    {parse an expression term;  returns the translated expression term;
  243.     detects subexpressions, set literals and lvalues(variable names)}
  244. var
  245.    ex: string;
  246.    builtin: boolean;
  247.  
  248. begin
  249.    if debug_parse then write(' <term>');
  250.  
  251.    if (toktype = identifier) and (cursym <> nil) then
  252.       builtin := cursym^.symtype = ss_builtin
  253.    else
  254.       builtin := false;
  255.  
  256.    (* process pos(c,str) and pos(str,str) *)
  257.    if builtin and (length(tok) = 3) and (tok = 'POS') then
  258.    begin
  259.       if debug_parse then write(' <pos>');
  260.  
  261.       gettok;   {consume the keyword}
  262.       if tok[1] <> '(' then
  263.          syntax('"(" expected (pterm.pos)');
  264.       
  265.       gettok;   {consume the (}
  266.       ex := pexpr;
  267.       if exprtype = 'c' then
  268.          ex := 'cpos(' + ex
  269.       else
  270.          ex := 'spos(' + ex;
  271.  
  272.       gettok;   {consume the ,}
  273.       ex := ex + ',' + pexpr;
  274.       gettok;   {consume the )}
  275.       pterm := ex + ')';
  276.       cexprsym := intsym;
  277.    end
  278.    else
  279.  
  280.    (* process chr(n) *)
  281.    if builtin and (length(tok) = 3) and (tok = 'CHR') then
  282.    begin
  283.       if debug_parse then write(' <chr>');
  284.  
  285.       gettok;   {consume the keyword}
  286.       if tok[1] <> '(' then
  287.          syntax('"(" expected (pterm.chr)');
  288.       
  289.       gettok;   {consume the (}
  290.       ex := pexpr;
  291.       gettok;   {consume the )}
  292.  
  293.       if isnumber(ex) then
  294.          ex := numlit(htoi(ex))
  295.       else
  296.          ex := 'chr('+ex+')';
  297.  
  298.       pterm := ex;
  299.       cexprsym := charsym;
  300.    end
  301.    else
  302.  
  303.    (* translate NOT term into !term *)
  304.    if builtin and (length(tok) = 3) and (tok = 'NOT') then
  305.    begin
  306.       if debug_parse then write(' <not>');
  307.  
  308.       gettok;
  309.       pterm := '!' + pterm;
  310.       cexprsym := boolsym;
  311.    end
  312.    else
  313.  
  314.    (* process port/memory array references *)
  315.    if builtin and ( ((length(tok) = 3) and (tok = 'MEM')    ) or
  316.                     ((length(tok) = 4) and ((tok = 'PORT') or (tok = 'MEMW')) ) or
  317.                     ((length(tok) = 5) and (tok = 'PORTW')  ) ) then
  318.    begin
  319.       if debug_parse then write(' <port>');
  320.  
  321.       if tok = 'PORT'  then ex := 'inportb('    else
  322.       if tok = 'PORTW' then ex := 'inport('     else
  323.       if tok = 'MEM'   then ex := 'peekb('      else
  324.                             ex := 'peek(';
  325.  
  326.       gettok;     {consume the keyword}
  327.       gettok;     {consume the [ }
  328.  
  329.       repeat
  330.          ex := ex + pexpr;
  331.          if tok[1] = ':' then
  332.          begin
  333.             gettok;
  334.             ex := ex + ',';
  335.          end;
  336.       until (tok[1] = ']') or recovery;
  337.  
  338.       gettok;     {consume the ] }
  339.       pterm := ex + ')';
  340.       cexprsym := intsym;
  341.    end
  342.    else
  343.  
  344.    (* translate bitwise not (mt+) *)
  345.    if (tok[1] = '?') or (tok[1] = '~') or (tok[1] = '\') then
  346.    begin
  347.       if debug_parse then write(' <bitnot>');
  348.  
  349.       gettok;
  350.       pterm := '!' + pterm;         {what is a bitwise NOT in c?}
  351.    end
  352.    else
  353.  
  354.    (* process unary minus *)
  355.    if (length(tok) = 1) and (tok[1] = '-') then
  356.    begin
  357.       if debug_parse then write(' <unary>');
  358.  
  359.       gettok;
  360.       pterm := '-' + pterm;
  361.    end
  362.    else
  363.  
  364.    (* translate address-of operator *)
  365.    if tok[1] = '@' then
  366.    begin
  367.       if debug_parse then write(' <ref>');
  368.  
  369.       gettok;  {consume the '@'}
  370.       ex := plvalue;
  371.       make_pointer(ex);
  372.       pterm := ex;
  373.    end
  374.    else
  375.  
  376.    (* translate address-of operator *)
  377.    if builtin and ((length(tok) = 4) and (tok = 'ADDR')) then
  378.    begin
  379.       if debug_parse then write(' <addr>');
  380.  
  381.       gettok;  {consume the 'ADDR'}
  382.       gettok;  {consume the (}
  383.       ex := plvalue;
  384.       make_pointer(ex);
  385.       gettok;  {consume the )}
  386.       pterm := ex;
  387.    end
  388.    else
  389.  
  390.    (* pass numbers *)
  391.    if toktype = number then
  392.    begin
  393.       if debug_parse then write(' <number>');
  394.  
  395.       case exprtype of
  396.          'D':  begin
  397.                   pterm := tok + 'L';
  398.                   gettok;
  399.                   cexprsym := longsym;
  400.                end;
  401.  
  402.          'f':  begin
  403.                   pterm := tok + '.0';
  404.                   gettok;
  405.                   cexprsym := doublesym;
  406.                end;
  407.  
  408.       else     begin
  409.                   pterm := tok;
  410.                   gettok;
  411.                   cexprsym := intsym;
  412.                end;
  413.       end;
  414.    end
  415.    else
  416.  
  417.    if toktype = longnumber then
  418.    begin
  419.       if debug_parse then write(' <long.number>');
  420.  
  421.       pterm := tok;
  422.       gettok;
  423.       cexprsym := longsym;
  424.    end
  425.    else
  426.  
  427.    if toktype = realnumber then
  428.    begin
  429.       if debug_parse then write(' <real.number>');
  430.  
  431.       pterm := tok;
  432.       gettok;
  433.       cexprsym := doublesym;
  434.    end
  435.    else
  436.  
  437.    (* pass strings *)
  438.    if toktype = strng then
  439.    begin
  440.       if debug_parse then write(' <string>');
  441.  
  442.       pterm := tok;
  443.       gettok;
  444.       cexprsym := stringsym; {charptrsym;}
  445.    end
  446.    else
  447.  
  448.    (* pass characters *)
  449.    if toktype = chars then
  450.    begin
  451.       if debug_parse then write(' <char>');
  452.  
  453.       pterm := tok;
  454.       gettok;
  455.       cexprsym := charsym;
  456.    end
  457.    else
  458.  
  459.    (* pass sub expressions *)
  460.    if tok[1] = '(' then
  461.    begin
  462.       if debug_parse then write(' <subexp>');
  463.  
  464.       gettok;
  465.       pterm := '(' + pexpr + ')';
  466.       gettok;
  467.    end
  468.    else
  469.  
  470.    (* translate literal sets *)
  471.    if tok[1] = '[' then
  472.    begin
  473.       if debug_parse then write(' <setlit>');
  474.  
  475.       gettok;
  476.       pterm := psetof;
  477.       gettok;
  478.       cexprsym := voidsym;
  479.    end
  480.  
  481.    (* otherwise the term will be treated as an lvalue *)
  482.    else
  483.       pterm := plvalue;
  484. end;
  485.  
  486.  
  487. (********************************************************************)
  488. function plvalue: string;
  489.    {parse and translate an lvalue specification and return the translated
  490.     lvalue as a string}
  491.  
  492. var
  493.    lv:       string;
  494.    ex:       string;
  495.    prefix:   string40;
  496.    idok:     boolean;
  497.    sym:      symptr;
  498.    bsym:     symptr;
  499.    pvars:    integer;
  500.    recid:    string40;
  501.  
  502. begin
  503.  
  504.    if debug_parse then write(' <lvalue>');
  505.    plvalue := 'lvalue';
  506.  
  507. (* lvalues must begin with an identifier in pascal *)
  508.    if toktype <> identifier then
  509.    begin
  510.       syntax('Identifier expected (plvalue)');
  511.       exit;
  512.    end;
  513.  
  514. (* assign initial part of the lvalue *)
  515.    idok := false;
  516.    prefix := '';
  517.  
  518.    sym := cursym;
  519.    if sym = nil then
  520.    begin
  521.       sym := voidsym;
  522.       lv := ltok;
  523.    end
  524.    else
  525.       lv := sym^.repid;          {use replacement identifier}
  526.  
  527.    recid := lv;
  528.    cexprsym := sym;
  529.    while cexprsym^.symtype = ss_subtype do
  530.       cexprsym := cexprsym^.parent;
  531.  
  532.    {dereference VAR paremter pointers}
  533.    if sym^.parcount = -2 then
  534.    begin
  535.       if debug_parse then write(' <var.deref>');
  536.       prefix := '*';
  537.    end;
  538.  
  539.    {prefix with pointer if this is a member identifier and a
  540.     'with' is in effect}
  541.    if (sym^.parcount < 0) and (sym^.pvar > 0) and (withlevel > 0) then
  542.    begin
  543.       if debug_parse then write(' <with.deref>');
  544.       prefix := 'with'+itoa(withlevel)+'->';
  545.    end;
  546.  
  547.    {check for typecasts}
  548.    gettok;
  549.    if (tok[1] = '(') then
  550.    begin
  551.       if (sym <> voidsym) and (cexprsym^.symtype <> ss_func) then
  552.       begin
  553.          lv := '(' + lv + ') ';
  554.          if debug_parse then write(' <cast>');
  555.       end;
  556.    end;
  557.    
  558.  
  559. (* process a list of qualifiers and modifiers *)
  560.  
  561.    repeat
  562. (*
  563. if debug then
  564. writeln('lv1=',prefix,lv,' ty=',cexprsym^.parent^.repid,' b=',cexprsym^.base);
  565. *)
  566.       if toktype = identifier then
  567.       begin
  568.  
  569.          if cursym = nil then
  570.             cexprsym := voidsym
  571.          else
  572.          
  573.          {find record member types}
  574.          begin
  575.             sym := cursym;
  576.             cexprsym := sym;
  577.             ltok := sym^.repid;          {use replacement identifier}
  578.          end;
  579.          
  580.       end;
  581.       
  582.       (* process identifiers (variable or field names) *)
  583.       if idok and (toktype = identifier) then
  584.       begin
  585.          if debug_parse then write(' <ident>');
  586.  
  587.          ex := ltok;
  588.          idok := false;
  589.          lv := lv + ex;
  590.          gettok;
  591.       end
  592.       else
  593.  
  594.       (* pointers *)
  595.       if (length(tok) = 1) and (tok[1] = '^') then
  596.       begin
  597.          if debug_parse then write(' <deref>');
  598.  
  599.          prefix := '*' + prefix;
  600.          gettok;
  601.          if (cexprsym^.symtype = ss_scalar) and
  602.             (cexprsym^.parent^.symtype = ss_pointer) then
  603.             cexprsym := cexprsym^.parent;
  604.  
  605.          cexprsym := cexprsym^.parent;
  606.        { if cexprsym^.symtype = ss_pointer then
  607.             cexprsym := cexprsym^.parent; } {hack??}
  608.       end
  609.       else
  610.  
  611.       (* pointer members *)
  612.       if (length(tok) = 2) and (tok[1] = '^') and (tok[2] = '.') then
  613.       begin
  614.          if debug_parse then write(' <ptr.deref>');
  615.  
  616.          lv := lv + '->';
  617.          gettok;
  618.          idok := true;
  619.          cexprsym := cexprsym^.parent;
  620.       end
  621.       else
  622.  
  623.       (* record members *)
  624.       if (length(tok) = 1) and (tok[1] = '.') then
  625.       begin
  626.          if debug_parse then write(' <member>');
  627.  
  628.          if prefix = '*' then     {translate *id. into id->}
  629.          begin
  630.             prefix := '';
  631.             lv := lv + '->';
  632.          end
  633.          else
  634.             lv := lv + '.';
  635.          idok := true;
  636.          gettok;
  637.          cexprsym := cexprsym^.parent;
  638.       end
  639.       else
  640.  
  641.       (* subscripts, pointer subscripts *)
  642.       if (tok[1] = '[') or
  643.          ((length(tok) = 2) and (tok[1] = '^') and (tok[2] = '[')) then
  644.       begin
  645.          if debug_parse then
  646.             if tok[1] = '^' then
  647.                write(' <ptr.subs>')
  648.             else
  649.                write(' <subs>');
  650.  
  651.          if tok[1] = '^' then
  652.          begin
  653.             cexprsym := cexprsym^.parent;
  654.             lv := lv + '[0]';
  655.          end;
  656.          bsym := cexprsym;
  657.  
  658.          if copy(prefix,1,1) = '*' then
  659.             prefix := '';       {replace '*id[' with 'id['}
  660.  
  661.          lv := lv + '[';
  662.          gettok;
  663.  
  664.          repeat
  665.             ex := pexpr;
  666.  
  667.             if tok[1] = ',' then
  668.             begin
  669.                lv := lv + ex + '][';
  670.                gettok;
  671.                subtract_base(ex,bsym^.base);
  672.             end;
  673.          until tok[1] = ']';
  674.  
  675.          subtract_base(ex,bsym^.base);
  676.          if bsym^.symtype = ss_array then
  677.             bsym := bsym^.parent
  678.          else
  679.          begin
  680.             bsym := bsym^.parent;
  681.             if bsym^.symtype = ss_array then 
  682.                bsym := bsym^.parent;   {hack??}
  683.          end;
  684.          lv := lv + ex + ']';
  685.  
  686.          cexprsym := bsym;
  687.          gettok;
  688. (*
  689. if debug then
  690. writeln('...lv2=',lv,' ty=',bsym^.repid,' b=',bsym^.base);
  691. *)
  692.       end
  693.       else
  694.  
  695.       (* function calls *)
  696.       if tok[1] = '(' then
  697.       begin
  698.          if debug_parse then write(' <param>');
  699.  
  700.          pvars := 0;
  701.          bsym := cexprsym;           {determine return type}
  702.          pvars := cexprsym^.pvar;    {determine parameter types}
  703.  
  704.          lv := lv + '(';
  705.          gettok;
  706.  
  707.          while tok[1] <> ')' do
  708.          begin
  709.             ex := pexpr;
  710.             if (pvars and 1) = 1 then     {prefix VAR paremeters}
  711.                make_pointer(ex);
  712.  
  713.             lv := lv + ex;
  714.             pvars := pvars shr 1;
  715.  
  716.             if (tok[1] = ',') or (tok[1] = ':') then
  717.             begin
  718.                lv := lv + ',';
  719.                gettok;
  720.             end;
  721.          end;
  722.  
  723.          lv := lv + ')';
  724.          gettok;
  725.          cexprsym := bsym;
  726.       end
  727.       else
  728.  
  729. (* otherwise just return what was found so far *)
  730.       begin
  731.  
  732.          (* add dummy param list to function calls where the proc
  733.             expects no parameters *)
  734.          if sym <> nil then
  735.          begin
  736.             if (not iscall(lv)) and (sym^.parcount >= 0) then
  737.                lv := lv + '()';
  738.          end;
  739.  
  740.          if length(prefix)+length(lv) >= 255 then
  741.             warning('Expression too long');
  742.          plvalue := prefix + lv;
  743. (*
  744. if debug then
  745. writeln('...lv3=',prefix,lv,' ty=',cexprsym^.parent^.repid,' b=',cexprsym^.base);
  746. *)
  747.          exit;
  748.       end;
  749.  
  750.    until recovery;
  751.  
  752.    plvalue := prefix + lv;
  753. end;
  754.  
  755.  
  756. (********************************************************************)
  757. function pexpr: string;
  758.    {top level expression parser; parse and translate an expression and
  759.     return the translated expr}
  760. var
  761.    ex:       string;
  762.    ty:       char;
  763.    ex2:      string;
  764.    ty2:      char;
  765.    endexpr:  boolean;
  766.  
  767.    procedure relop(newop: string40);
  768.    begin
  769.       if debug_parse then write(' <relop>');
  770.  
  771.       gettok;        {consume the operator token}
  772.  
  773.       ex2 := pterm;  {get the second term}
  774.       ty2 := exprtype;
  775.  
  776.       {use strcmp if either param is a string}
  777.       if ty = 's' then
  778.       begin
  779.          if ty2 = 's' then
  780.             ex := 'strcmp(' + ex + ',' + ex2 + ') ' + newop + ' 0'
  781.          else
  782.          if ex2[1] = '''' then
  783.             ex := 'strcmp(' + ex + ',"' +
  784.                      copy(ex2,2,length(ex2)-2) + '") ' + newop + ' 0'
  785.          else
  786.             ex := 'strcmp(' + ex + ',ctos(' + ex2 + ')) ' + newop + ' 0'
  787.       end
  788.       else
  789.  
  790.       if ty = 'c' then
  791.       begin
  792.          if ty2 = 's' then
  793.             ex := 'strcmp(ctos(' + ex + '),' + ex2 + ') ' + newop + ' 0'
  794.          else
  795.             ex := ex + ' ' + newop + ' ' + ex2
  796.       end
  797.  
  798.       else
  799.          ex := ex + ' ' + newop + ' ' + ex2;
  800.  
  801.       cexprsym := boolsym;
  802.    end;
  803.  
  804.  
  805.    procedure addop;
  806.  
  807.       procedure add_scat;
  808.       var
  809.          p,q: integer;
  810.  
  811.       begin
  812.          {find end of control string}
  813.          p := 7;  {position of 'scat("%'}
  814.          while (ex[p] <> '"') or
  815.                ((ex[p] = '"') and (ex[p-1] = '\') and (ex[p-2] <> '\')) do
  816.             p := succ(p);
  817.          p := succ(p);
  818.  
  819.          {add literals to the control string if possible}
  820.             {note: need to add escape conversions and % doubling}
  821.          if (ex2[1] = '''') or (ex2[1] = '"') then
  822.          begin
  823.             ex := copy(ex,1,p-2) + 
  824.                   copy(ex2,2,length(ex2)-2) +
  825.                   copy(ex,p-1,length(ex)-p+2);
  826.          end
  827.  
  828.          else {add a parameter to the control string}
  829.             ex := copy(ex,1,p-2) + '%' + ty2 +
  830.                   copy(ex,p-1,length(ex)-p+1) + ',' + ex2 + ')';
  831.  
  832.          cexprsym := stringsym; {charptrsym??;}
  833.       end;
  834.  
  835.    begin
  836.       if debug_parse then write(' <addop>');
  837.  
  838.       gettok;        {consume the operator token}
  839.  
  840.       ex2 := pterm;  {get the second term}
  841.       ty2 := exprtype;
  842. (*
  843. if debug then
  844. writeln('ex{',ex,'}',ty,' ex2{',ex2,'}',ty2);   
  845. *)
  846.       {continue adding string params to scat control string}
  847.       if (ex[5] = '(') and (copy(ex,1,4) = 'scat') then
  848.          add_scat
  849.       else
  850.  
  851.       {start new scat call if any par is a string}
  852.       if strtype(ty) or strtype(ty2) then
  853.       begin
  854.          if (ex[1] = '''') or (ex[1] = '"') then
  855.             ex := 'scat("' + copy(ex,2,length(ex)-2) + '")'
  856.          else
  857.             ex := 'scat("%' + ty + '",' + ex + ')';
  858.          add_scat;
  859.       end
  860.       else
  861.          ex := ex + ' + ' + ex2;
  862.  
  863. (*
  864. if debug then
  865. writeln('ex=',ex);   
  866. *)
  867.    end;
  868.  
  869.    procedure mulop(newop: string40);
  870.    begin
  871.       if debug_parse then write(' <mulop>');
  872.  
  873.       gettok;        {consume the operator token}
  874.  
  875.       ex2 := pterm;  {get the second term}
  876.       ex := ex + ' ' + newop + ' ' + ex2;
  877.    end;
  878.  
  879.    procedure andop(newop: char);
  880.    begin
  881.       if debug_parse then write(' <andop>');
  882.  
  883.       gettok;        {consume the operator token}
  884.  
  885.       ex2 := pterm;  {get the second term}
  886.       ty2 := exprtype;
  887.  
  888.       {boolean and/or?}
  889.       if (ty = 'b') or (ty2 = 'b') then
  890.       begin
  891.          ex := ex + ' ' + newop + newop + ' ' + ex2;
  892.          cexprsym := boolsym;
  893.       end
  894.       else  {otherwise bitwise}
  895.          ex := ex + ' ' + newop + ' ' + ex2;
  896.    end;
  897.  
  898.  
  899. begin {pexpr}
  900.  
  901.    if debug_parse then write(' <expr>');
  902.    ex := pterm;
  903.    ty := exprtype;
  904.    endexpr := false;
  905.  
  906.    while not endexpr do
  907.  
  908.       (* process operators *)
  909.       case length(tok) of
  910.           1: if      tok[1] = '>' then relop(tok)
  911.              else if tok[1] = '<' then relop(tok)
  912.              else if tok[1] = '=' then relop('==')
  913.              else if tok[1] = '+' then addop
  914.              else if tok[1] = '-' then mulop(tok)
  915.              else if tok[1] = '*' then mulop(tok)
  916.              else if tok[1] = '/' then mulop(tok)
  917.              else if tok[1] = '&' then mulop(tok)  {mt+}
  918.              else if tok[1] = '!' then mulop('|')  {mt+}
  919.              else if tok[1] = '|' then mulop('|')  {mt+}
  920.              else endexpr := true;
  921.  
  922.           2: if      (tok[1] = '>') and (tok[2] = '=') then relop(tok)
  923.              else if (tok[1] = '<') and (tok[2] = '=') then relop(tok)
  924.              else if (tok[1] = '<') and (tok[2] = '>') then relop('!=')
  925.              else if (tok[1] = 'O') and (tok[2] = 'R') then andop('|')
  926.  
  927.                         (* translate the expr IN set operator *)
  928.              else if (tok[1] = 'I') and (tok[2] = 'N') then
  929.                 begin
  930.                    gettok;
  931.                    ex := 'inset('+ex+',' + pterm + ')';
  932.                 end
  933.              else endexpr := true;
  934.  
  935.           3: if      (tok[1]='D') and (tok[2]='I') and (tok[3]='V') then mulop('/')
  936.              else if (tok[1]='M') and (tok[2]='O') and (tok[3]='D') then mulop('%')
  937.              else if (tok[1]='S') and (tok[2]='H') and (tok[3]='R') then mulop('>>')
  938.              else if (tok[1]='S') and (tok[2]='H') and (tok[3]='L') then mulop('<<')
  939.              else if (tok[1]='X') and (tok[2]='O') and (tok[3]='R') then mulop('^')
  940.              else if (tok[1]='A') and (tok[2]='N') and (tok[3]='D') then andop('&')
  941.              else endexpr := true;
  942.  
  943.         else endexpr := true;
  944.       end;
  945.  
  946.  
  947.    (* ran out of legal expression operators; return what we found *)
  948.    if length(ex) >= 255 then
  949.       warning('Expression too long');
  950.  
  951.    pexpr := ex;
  952.  
  953. (*
  954. write('ex=',ex,' ty=',exprtype);
  955. if cexprsym=nil then
  956.      writeln(' nil')
  957. else writeln(' sym=',cexprsym^.repid);
  958. *)
  959.  
  960. end;
  961.  
  962.  
  963.  
  964.